package tech.dongling.boot.ioc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.dongling.boot.anno.Component;
import tech.dongling.boot.anno.ProtocolMapping;
import tech.dongling.boot.anno.HttpProcessor;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Bean扫描器，用于扫描@Component注解的类并自动注册
 */
public class BeanScanner {
    private static final Logger logger = LoggerFactory.getLogger(BeanScanner.class);

    private final LightIocContainer ioc;
    private final Map<String, Object> beanInstances = new HashMap<>();

    public BeanScanner(LightIocContainer ioc) {
        this.ioc = ioc;
    }

    /**
     * 扫描指定包下的所有类
     */
    public void scan(String basePackage) {
        logger.info("Starting to scan package: {}", basePackage);

        try {
            // 获取包下的所有类
            Set<Class<?>> classes = PackageScanner.scanClasses(basePackage);

            for (Class<?> clazz : classes) {
                if (clazz.isAnnotationPresent(Component.class)) {
                    registerBean(clazz);
                }
            }

            logger.info("Bean scanning completed, found {} beans", beanInstances.size());

        } catch (Exception e) {
            logger.error("Error during bean scanning: {}", e.getMessage(), e);
        }
    }

    /**
     * 递归注册Bean，优先注册依赖
     */
    public void registerBean(Class<?> clazz) {
        if (beanInstances.containsValue(clazz)) return;
        try {
            Component component = clazz.getAnnotation(Component.class);
            String beanName = component != null && !component.value().isEmpty() ? component.value() : getDefaultBeanName(clazz);
            if (beanInstances.containsKey(beanName)) return;
            Object bean = createBeanInstance(clazz);
            ioc.register(beanName, bean);
            beanInstances.put(beanName, bean);
            if (bean instanceof HttpProcessor && clazz.isAnnotationPresent(ProtocolMapping.class)) {
                registerProtocolMapping(bean, clazz);
            }
            logger.debug("Registered bean: {} -> {}", beanName, clazz.getSimpleName());
        } catch (Exception e) {
            logger.error("Failed to register bean {}: {}", clazz.getSimpleName(), e.getMessage(), e);
        }
    }

    /**
     * 创建Bean实例，递归注册依赖
     */
    private Object createBeanInstance(Class<?> clazz) throws Exception {
        Constructor<?>[] constructors = clazz.getConstructors();
        // 优先无参
        for (Constructor<?> constructor : constructors) {
            if (constructor.getParameterCount() == 0) {
                return constructor.newInstance();
            }
        }
        // 有参构造，递归注册依赖
        for (Constructor<?> constructor : constructors) {
            Class<?>[] paramTypes = constructor.getParameterTypes();
            Object[] args = new Object[paramTypes.length];
            boolean canInject = true;
            for (int i = 0; i < paramTypes.length; i++) {
                Object dep = getBeanOfType(paramTypes[i]);
                if (dep == null) {
                    registerBean(paramTypes[i]);
                    dep = getBeanOfType(paramTypes[i]);
                }
                if (dep == null) {
                    canInject = false;
                    break;
                }
                args[i] = dep;
            }
            if (canInject) {
                return constructor.newInstance(args);
            }
        }
        throw new RuntimeException("No suitable constructor found for " + clazz.getName());
    }

    /**
     * 检查是否有指定类型的Bean
     */
    private boolean hasBeanOfType(Class<?> type) {
        for (Object bean : beanInstances.values()) {
            if (type.isAssignableFrom(bean.getClass())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取指定类型的Bean
     */
    private Object getBeanOfType(Class<?> type) {
        for (Object bean : beanInstances.values()) {
            if (type.isAssignableFrom(bean.getClass())) {
                return bean;
            }
        }
        return null;
    }

    /**
     * 注册协议映射
     */
    private void registerProtocolMapping(Object bean, Class<?> clazz) {
        ProtocolMapping mapping = clazz.getAnnotation(ProtocolMapping.class);
        String[] paths = mapping.value();

        for (String path : paths) {
            ioc.registerProtocolHandler(path, bean);
            logger.debug("Registered protocol mapping: {} -> {}", path, clazz.getSimpleName());
        }
    }

    /**
     * 获取默认Bean名称
     */
    private String getDefaultBeanName(Class<?> clazz) {
        String className = clazz.getSimpleName();
        // 将首字母小写
        return className.substring(0, 1).toLowerCase() + className.substring(1);
    }
} 